/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package javaapplication1;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 *
 * @author new
 */
public class NumberHandler {
    
    public NumberHandler() throws FileNotFoundException, IOException{
        getNumberAfteMnemonicTable();
    }

    public String calculate(String inStr){
        boolean hasOperators = false;
        String temp = new String(inStr);
        int firstHalfNumber = 0;
        int latterHalfNumber = 0;
        for(int i = 0; i < inStr.length(); i++){
            if(temp.charAt(i) == '('){
                firstHalfNumber++;
            }
            if(temp.charAt(i) == ')'){
                latterHalfNumber++;
            }
        }
        if(firstHalfNumber > latterHalfNumber){
            System.out.println("Missing )");
            System.exit(0);
        }
        if(firstHalfNumber < latterHalfNumber){
            System.out.println("Missing (");
            System.exit(0);
        }
        int firstHalf = 0;
        int nextFirstHalf = 0;
        int latterHalf = 0;
        while(temp.contains("(")){
            firstHalf = temp.indexOf('(');
            nextFirstHalf = temp.indexOf('(', firstHalf + 1);
            latterHalf = temp.indexOf(')');
            if(latterHalf < firstHalf){
                System.out.println("Missing (");
                System.exit(0);
            }
            if(nextFirstHalf == -1){
                nextFirstHalf = temp.length();
            }
            while(nextFirstHalf < latterHalf){
                firstHalf = nextFirstHalf;
                nextFirstHalf = temp.indexOf('(', nextFirstHalf + 1);
            }
            temp = temp.substring(0, firstHalf)
                    + doOperator(temp.substring(firstHalf + 1, latterHalf))
                    + temp.substring(latterHalf + 1);
            
        }
        temp = doOperator(temp);
        for(int i = 0; i < operatorsLength; i++){
            if(temp.contains("" + operators.charAt(i))){
                System.out.println("" + operators.charAt(i) + " syntax error.");
                System.exit(0);
            }
        }
        return temp;
    }

    public String toHexAfterMnemonic(String inStr){
        Pattern pattern;
        Matcher matcher;
        String result = new String(inStr);
        for(int i = 0; i< 20; i++){
            if(numberAfteMnemonicTable[i] != null){
                pattern = Pattern.compile(numberAfteMnemonicTable[i],Pattern.CASE_INSENSITIVE);
                matcher =pattern.matcher(result);
                try{
                    if(matcher.find()){
                        String temp  = matcher.group();
                        if((i == 2) && (temp.equals("A") || temp.equals("DPTR"))){
                            continue;
                        }
                        if((i == 0) && ((temp.equals("DPTR")) || temp.equals("R0") || temp.equals("R1") || temp.equals("R2") || temp.equals("R3") || temp.equals("DPH") || temp.equals("DPL") || temp.equals("SPH") || temp.equals("SPL"))){
                            continue;
                        }
                        if((i == 3) && (temp.equals("R0") || temp.equals("R1") || temp.equals("R2") || temp.equals("R3") || temp.equals("DPH") || temp.equals("DPL") || temp.equals("SPH") || temp.equals("SPL"))){
                            continue;
                        }
                        temp = toHex(temp);
                        result = matcher.replaceFirst(temp);
                    }
                }catch(IllegalStateException e){

                }
            }
        }

        return result;
    }



    public String toHex(String temp) {
        String result = new String(temp);
        boolean hasChanged = false;
        boolean isNegative = false;
        if(result.contains("-")){
            isNegative = true;
        }
        if((!hasChanged) && isBinary(result)){
            result = binaryToHex(result);
            
            hasChanged = true;
        }
        if((!hasChanged) && isHex(result)){
            result = hexToHex(result);
            hasChanged = true;
        }
        if((!hasChanged) && isDecimal(result)){
            result = decimalToHex(result);
            hasChanged = true;
        }
        if(hasChanged){
            int number = Integer.valueOf(result, 16);
            if(isNegative){
                if(number < 256){
                    result = Integer.toHexString(256 - number);
                } else {
                    if(number < 65536){
                        result = Integer.toHexString(65536 - number);
                    } else {
                        System.out.println("Too large number.");
                        System.exit(1);
                    }
                }
            }
            if(result.length() % 2 != 0){
                result = "0" + result;
            }
        }
        if(hasChanged){
            return result;
        } else {
            System.out.println(temp + " is not a number.");
            System.exit(0);
            return result;
        }
    }

    private static String hexToHex(String result) {
        Pattern pattern;
        Matcher matcher;
        String temp = new String(result);

        pattern = Pattern.compile("[0-9a-fA-F]+",Pattern.CASE_INSENSITIVE);
        matcher =pattern.matcher(temp);
        matcher.find();
        return matcher.group();
    }

    private static String binaryToHex(String result) {
        Pattern pattern;
        Matcher matcher;
        String temp = new String(result);

        pattern = Pattern.compile("[01]+",Pattern.CASE_INSENSITIVE);
        matcher =pattern.matcher(temp);
        matcher.find();
        return Integer.toHexString(Integer.valueOf(matcher.group(),2));
    }

    private static String decimalToHex(String result) {
        Pattern pattern;
        Matcher matcher;
        String temp = new String(result);

        pattern = Pattern.compile("\\d+",Pattern.CASE_INSENSITIVE);
        matcher =pattern.matcher(temp);
        matcher.find();
        return Integer.toHexString(Integer.valueOf(matcher.group(),10));
    }

    public static boolean isBinary(String result) {
        Pattern pattern;
        Matcher matcher;
        String temp = new String(result);

        pattern = Pattern.compile("[01]+B",Pattern.CASE_INSENSITIVE);
        matcher =pattern.matcher(temp);
        return matcher.matches();
    }
    
    public static boolean isDecimal(String result) {
        Pattern pattern;
        Matcher matcher;
        String temp = new String(result);

        pattern = Pattern.compile("\\d+",Pattern.CASE_INSENSITIVE);
        matcher =pattern.matcher(temp);
        return matcher.matches();
    }

    public static boolean isHex(String result) {
        Pattern pattern;
        Matcher matcher;
        String temp = new String(result);

        pattern = Pattern.compile("[0-9a-fA-F]+H",Pattern.CASE_INSENSITIVE);
        matcher =pattern.matcher(temp);
        return matcher.matches();
    }

    private String doOperator(String in){
        String result = new String(in);
        Pattern pattern;
        Pattern numberPattern;
        Matcher matcher;
        Matcher numberMatcher;
        String temp = new String("");

        pattern = Pattern.compile("!\\s*\\w+",Pattern.CASE_INSENSITIVE);
        numberPattern = Pattern.compile("(?<=!\\s{0,65536})\\w+", Pattern.CASE_INSENSITIVE);
        matcher =pattern.matcher(result);
        while(matcher.find()){
            numberMatcher = numberPattern.matcher(matcher.group());
            numberMatcher.find();
            temp = toHex(numberMatcher.group());
            temp = "" + ~(Integer.valueOf(temp, 16));
            matcher.replaceFirst(temp);
        }

        pattern = Pattern.compile("~\\s*\\w+",Pattern.CASE_INSENSITIVE);
        numberPattern = Pattern.compile("(?<=~\\s{0,65536})\\w+", Pattern.CASE_INSENSITIVE);
        matcher =pattern.matcher(result);
        while(matcher.find()){
            numberMatcher = numberPattern.matcher(matcher.group());
            numberMatcher.find();
            temp = toHex(numberMatcher.group());
            temp = "" + ~(Integer.valueOf(temp, 16));
            matcher.replaceFirst(temp);
        }
        return result;
    }
    
    private void getNumberAfteMnemonicTable() {

        numberAfteMnemonicTable[0] = "\\w{1,65536}(?=\\s{0,65536},\\s{0,65536}\\bA\\b)";
        numberAfteMnemonicTable[1] = "(?<=#\\s{0,65536})\\w{1,65536}";
        numberAfteMnemonicTable[2] = "(?<=\\bA\\b\\s{0,65536},\\s{0,65536}@\\s{0,65536})\\w{1,65536}";
        numberAfteMnemonicTable[3] = "(?<=\\bA\\b\\s{0,65536},\\s{0,65536})\\w{1,65536}";
        numberAfteMnemonicTable[4] = "(?<=\\bPJMP\\b\\s{0,65536})\\w{1,65536}";
        numberAfteMnemonicTable[5] = "(?<=\\bPCALL\\b\\s{0,65536})\\w{1,65536}";
        numberAfteMnemonicTable[6] = "(?<=\\bJZ\\b\\s{0,65536})\\w{1,65536}";
        numberAfteMnemonicTable[7] = "(?<=\\bJNZ\\b\\s{0,65536})\\w{1,65536}";
        numberAfteMnemonicTable[8] = "(?<=\\bJC\\b\\s{0,65536})\\w{1,65536}";
        numberAfteMnemonicTable[9] = "(?<=\\bJNC\\b\\s{0,65536})\\w{1,65536}";
        numberAfteMnemonicTable[10] = "(?<=\\bJPO\\b\\s{0,65536})\\w{1,65536}";
        numberAfteMnemonicTable[11] = "(?<=\\bJPE\\b\\s{0,65536})\\w{1,65536}";
        numberAfteMnemonicTable[12] = "(?<=\\bJS\\b\\s{0,65536})\\w{1,65536}";
        numberAfteMnemonicTable[13] = "(?<=\\bJNS\\b\\s{0,65536})\\w{1,65536}";
        numberAfteMnemonicTable[14] = "(?<=\\bSJMP\\b\\s{0,65536})\\w{1,65536}";
        numberAfteMnemonicTable[15] = "(?<=\\bLJMP\\b\\s{0,65536})\\w{1,65536}";
        numberAfteMnemonicTable[16] = "(?<=\\bLCALL\\b\\s{0,65536})\\w{1,65536}";
        numberAfteMnemonicTable[17] = "(?<=\\bINT\\b\\s{0,65536})\\w{1,65536}";
        numberAfteMnemonicTable[18] = "(?<=\\bDJNZ\\b\\s{0,65536}\\w{1,65536}\\s{0,65536},\\s{0,65536})\\w{1,65536}";
        numberAfteMnemonicTable[19] = "(?<=(\\bCJNE\\b\\s{0,65536}\\w{1,65536}\\s{0,65536},\\s{0,65536}#\\s{0,65536}\\w{1,65536}\\s{0,65536},\\s{0,65536}))\\w{1,65536}";        
    }

    private String numberAfteMnemonicTable[] = new String[20];
    private String operators = "()!~*/%+-&|^";
    private int operatorsLength = operators.length();

}
